﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
using System.Xml.Linq;

namespace Configure
{
    public partial class Form1 : Form
    {
        private string configurationFile = "configuration.xml";
        private ServiceConfig config { get; set; }

        public Form1()
        {
            InitializeComponent();
            config = new ServiceConfig(this.configurationFile);

            this.ConfigurationLoad(this.configurationFile);

            this.SetConnectionType();
            this.SetJournalType();
        }

        private void btnSave_Click(object sender, EventArgs e)
        {
            this.ConfigurationSave();
            MessageBox.Show("Конфигурация сохранена", "Информация", MessageBoxButtons.OK, MessageBoxIcon.Information);
        }

        private void ConfigurationLoad(string configurationFileName)
        {
            /// Проверка конфигурационного файла
            config.ConfigurationCheck();

            fld1cVersion.Text = config.GetValue("1cVersion");
            fld1cUseJournal.Checked = config.GetBooleanValue("1cUseJournal");
            fldDeleteCommerceML.Checked = config.GetBooleanValue("DeleteCommerceML");

            fld1cPath.Text = config.GetValue("1cPath");
            fld1cServer.Text = config.GetValue("1cServer");
            fld1cRef.Text = config.GetValue("1cRef"); 
            fld1cUser.Text = config.GetValue("1cUser"); 
            fld1cPassword.Text = config.GetValue("1cPassword"); 
            fld1cConnectionString.Text = config.GetValue("1cConnectionString");
            fldEdexUri.Text = config.GetValue("RootUri"); 
            fldEdexEmail.Text = config.GetValue("EdexEmail"); 
            fldEdexPassword.Text = config.GetValue("EdexPassword");
            fldSyncDate.Value = config.GetDateTimeValue("SyncDate"); 
            fldSyncDay.Text = config.GetValue("SyncDay");

            //fld1cSuppliers.SelectedValue = settings.SingleOrDefault(r => r.Attribute("key").Value == "Suppliers").Value;
            fldEdexCompanyKey.SelectedValue = config.GetValue("EdexCompanyKey");

            switch (config.GetValue("1cConnectionType"))
            {
                case "file":
                    rbtnIsFileBase.Checked = true;
                    break;
                case "base":
                    rbtnIsDataBase.Checked = true;
                    break;
            }


            this.RefreshCompaniesBox(config.GetCompaniesCache());
            this.RefreshSuppliersBox(config.GetSuppliersCache());

            fldExecuteTimes.Text = String.Join("; ", config.GetExecuteTimes());
        }

        private void ConfigurationSave()
        {
            this.config.SetValue("1cVersion", fld1cVersion.Text);
            this.config.SetBooleanValue("1cUseJournal", fld1cUseJournal.Checked);
            this.config.SetBooleanValue("DeleteCommerceML", fldDeleteCommerceML.Checked);

            if (rbtnIsFileBase.Checked)
                this.config.SetValue("1cConnectionType", "file");

            if (rbtnIsDataBase.Checked)
                this.config.SetValue("1cConnectionType", "base");

            this.config.SetValue("1cPath", fld1cPath.Text);
            this.config.SetValue("1cServer", fld1cServer.Text);
            this.config.SetValue("1cRef", fld1cRef.Text);
            this.config.SetValue("1cUser", fld1cUser.Text);
            this.config.SetValue("1cPassword", fld1cPassword.Text);
            this.config.SetValue("1cConnectionString", fld1cConnectionString.Text);
            this.config.SetValue("ApiUri", System.IO.Path.Combine(fldEdexUri.Text, "API"));
            this.config.SetValue("RootUri", fldEdexUri.Text);
            this.config.SetValue("EdexEmail", fldEdexEmail.Text);
            this.config.SetValue("EdexPassword", fldEdexPassword.Text);
            if (fldEdexCompanyKey.SelectedValue != null)
            {
                this.config.SetValue("EdexCompanyKey", fldEdexCompanyKey.SelectedValue.ToString());
            }
            this.config.SetDateTimeValue("SyncDate", fldSyncDate.Value);
            this.config.SetValue("SyncDay", fldSyncDay.Text);

            //settings.SingleOrDefault(r => r.Attribute("key").Value == "Suppliers").Value = fld1cSuppliers.Text;

            var times = fldExecuteTimes.Text.Split(new[] { ';', ' ', ',' }).Where(r => !String.IsNullOrWhiteSpace(r));
            this.config.SaveExecuteTimes(times);

            var config = System.Configuration.ConfigurationManager.OpenExeConfiguration(System.Configuration.ConfigurationUserLevel.None);

            System.Configuration.ConfigurationManager.AppSettings["RootUri"] = fldEdexUri.Text;
            System.Configuration.ConfigurationManager.AppSettings["ApiUri"] = System.IO.Path.Combine(fldEdexUri.Text, "API");

            /// Сохраняем конфигурационный файл приложения
            config.Save(System.Configuration.ConfigurationSaveMode.Modified);
        }

        private void SetConnectionType()
        {
            fld1cServer.Visible = false;
            fld1cPath.Visible = false;
            fld1cRef.Visible = false;

            if (rbtnIsDataBase.Checked)
            {
                fld1cServer.Visible = true;
                fld1cRef.Visible = true;
            }

            if (rbtnIsFileBase.Checked)
            {
                fld1cPath.Visible = true;                
            }
        }

        private void SetJournalType()
        {
            fldSyncDate.Visible = false;
            fldSyncDay.Visible = false;

            if (fld1cUseJournal.Checked)
            {
                fldSyncDate.Visible = true;
                fldSyncDay.Visible = false;
            }
            else 
            {
                fldSyncDate.Visible = false;
                fldSyncDay.Visible = true;
            }
        }

        private string MakeConnectionString()
        {
            var connectionString = String.Empty;

            if (rbtnIsFileBase.Checked)
            {
                if (!String.IsNullOrWhiteSpace(fld1cPath.Text))
                    connectionString += String.Format(@"File=""{0}"";", fld1cPath.Text); 
            }

            if (rbtnIsDataBase.Checked)
            {
                if (!String.IsNullOrWhiteSpace(fld1cServer.Text))
                    connectionString += String.Format(@"Srvr=""{0}"";", fld1cServer.Text);

                if (!String.IsNullOrWhiteSpace(fld1cRef.Text))
                    connectionString += String.Format(@"Ref=""{0}"";", fld1cRef.Text);                
            }

            if (!String.IsNullOrWhiteSpace(fld1cUser.Text))
                connectionString += String.Format(@"Usr=""{0}"";", fld1cUser.Text);

            if (!String.IsNullOrWhiteSpace(fld1cPassword.Text))
                connectionString += String.Format(@"Pwd=""{0}"";", fld1cPassword.Text);

            fld1cConnectionString.Text = connectionString;
            return connectionString;
        }

        private void cmdCheck1C_Click(object sender, EventArgs e)
        {
            EDEX_1C2CommerceML.I1C context;

            try
            {
                context = Get1CContext();
        
                var suppliers = context.GetSuppliers();

                /// Сохраняем в кэш
                config.SaveSuppliersCache(suppliers);

                /// Выводим в UI
                this.RefreshSuppliersBox(suppliers);

                MessageBox.Show("Проверка подключения успешно завершена", "Информация", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Ошибка подключения", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void cmdCheckEdex_Click(object sender, EventArgs e)
        {
            try
            {
                var edex = new EdexApiClient.EdexApiContext(
                    config.GetValue("ApiUri"), 
                    config.GetValue("RootUri"), 
                    fldEdexEmail.Text, fldEdexPassword.Text);
                                
                var companyes = edex
                    .GetAllowedCompanies()
                    .ToDictionary(r => r.COMPANY.GUID_RECORD.ToString(), r => r.COMPANY.COMPANY_NAME);

                /// Сохраняем в кэш
                config.SaveCompaniesCache(companyes);

                /// Выводим в UI
                this.RefreshCompaniesBox(companyes);

                MessageBox.Show("Проверка подключения успешно завершена", "Информация", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Ошибка подключения", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void RefreshSuppliersBox(Dictionary<string, string> data)
        {
            /*
            fld1cSuppliers.DataSource = data
                .Select(r => new { r.Key, r.Value })
                .ToList();

            fld1cSuppliers.ValueMember = "Key";
            fld1cSuppliers.DisplayMember = "Value";*/
        }

        private void RefreshCompaniesBox(Dictionary<string, string> data)
        {
            fldEdexCompanyKey.DataSource = data
                .Select(r => new { r.Key, r.Value })
                .ToList();

            fldEdexCompanyKey.ValueMember = "Key";
            fldEdexCompanyKey.DisplayMember = "Value";
        }

        private void rbtnIsFileBase_CheckedChanged(object sender, EventArgs e)
        {
            this.SetConnectionType();
            this.MakeConnectionString();
        }

        private void rbtnIsDataBase_CheckedChanged(object sender, EventArgs e)
        {
            this.SetConnectionType();
            this.MakeConnectionString();
        }
        
        private void fld1cPath_Click_1(object sender, EventArgs e)
        {
            using (var dialog = new FolderBrowserDialog())
                if (dialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                    fld1cPath.Text = dialog.SelectedPath;
        }

        private void fld1cPath_TextChanged(object sender, EventArgs e)
        {
            this.MakeConnectionString();
        }

        private void fld1cServer_TextChanged(object sender, EventArgs e)
        {
            this.MakeConnectionString();
        }

        private void fld1cUser_TextChanged(object sender, EventArgs e)
        {
            this.MakeConnectionString();
        }

        private void fld1cPassword_TextChanged(object sender, EventArgs e)
        {
            this.MakeConnectionString();
        }

        private void cmdProcessToFile_Click(object sender, EventArgs e)
        {
            try
            {
                string path = GetPath("cml");

                this.MakeCommerceML(path);

                MessageBox.Show(String.Format("Операция успешно завершена. Файлы сохранены в директории {0}", path), "Информация", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Ошибка выполнения операции", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private void cmdProcessToSite_Click(object sender, EventArgs e)
        {
            try
            {
                string path = GetPath("cml");

                this.MakeCommerceML(path);
                this.SendCommerceML(path, fldDeleteCommerceML.Checked);

                MessageBox.Show("Операция успешно завершена", "Информация", MessageBoxButtons.OK, MessageBoxIcon.Information);
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Ошибка выполнения операции", MessageBoxButtons.OK, MessageBoxIcon.Error);                
            }
        }

        private string GetPath(string type)
        {
            string subfolder = "";

            switch(type)
            {
                case "cml": 
                    subfolder = "documents";
                    break;
                case "log": 
                    subfolder = "log";
                    break;
                default:
                    break;
            }

            string path = System.IO.Path.Combine(System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().Location), subfolder);

            if (!System.IO.Directory.Exists(path))
            {
                System.IO.Directory.CreateDirectory(path);
            }

            return path;
        }

        private void MakeCommerceML(string path)
        {
            EDEX_1C2CommerceML.I1C context;

            context = Get1CContext();

            if (fld1cUseJournal.Checked)
            {
                var documents = context.GetDocumentsByPeriod(fldSyncDate.Value.Date, DateTime.Today.AddDays(1));
                foreach (var document in documents)
                {
                    var commerceMLdocument = context.GetCommerceML(document);
                    this.ProcessCommerceML(path, commerceMLdocument);
                }
            }
            else
            {
                var documents = context.GetDocumentsByDay(int.Parse(fldSyncDay.Text));
                foreach (var document in documents)
                {
                    var commerceMLdocument = context.GetCommerceML(document);
                    this.ProcessCommerceML(path, commerceMLdocument);
                }
            }
        }

        private void ProcessCommerceML(string path, CommerceML.Version205.КоммерческаяИнформация document)
        {
            var suppliers = config.GetSuppliers();
            var log = this.GetLog();

            var item = document.Items
                .Cast<CommerceML.Version205.Документ>()
                .FirstOrDefault();

            var fileName = System.IO.Path.Combine(path, item.Ид + ".xml");

            if (!log.Contains(item.Ид))
            {
                if (suppliers.Any())
                {
                    if (!item.Контрагенты.Any(r => suppliers.Select(n => n.Key).Contains(r.Ид)))
                        return;
                }

                using (var writeStream = new System.IO.StreamWriter(fileName))
                {
                    System.Xml.Serialization.XmlSerializer serializer = new System.Xml.Serialization.XmlSerializer(typeof(CommerceML.Version205.КоммерческаяИнформация));
                    serializer.Serialize(writeStream, document);
                    writeStream.Close();
                }

                this.AddToLog(item.Ид);
            }
        }

        private async void SendCommerceML(string path, bool delete)
        {
            try
            {
                var edex = new EdexApiClient.EdexApiContext(fldEdexEmail.Text, fldEdexPassword.Text);
                edex.ChangeCompany(fldEdexCompanyKey.SelectedValue != null ? fldEdexCompanyKey.SelectedValue.ToString() : fldEdexCompanyKey.Text);

                foreach (var fileName in System.IO.Directory.GetFiles(path))
                {
                    try
                    {
                        using (var stream = new System.IO.FileStream(fileName, System.IO.FileMode.Open))
                        {
                            var result = await edex.UploadOutgoingInvoices(stream, "CommerceML.xml");
                            if (result.StatusCode != System.Net.HttpStatusCode.OK &&
                                result.StatusCode != System.Net.HttpStatusCode.NoContent)
                            {
                                var js = new System.Web.Script.Serialization.JavaScriptSerializer();
                                var data = js.Deserialize<EdexApiClient.ExceptionInfo>(result.Content.ReadAsStringAsync().Result);

                                throw new Exception(data.ExceptionMessage);
                            }

                            stream.Close();
                        }

                        if (delete) System.IO.File.Delete(fileName);
                    }
                    catch (Exception ex) { }
                }
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message, "Ошибка при отправке документа", MessageBoxButtons.OK, MessageBoxIcon.Error);
            }
        }

        private IEnumerable<string> GetLog()
        {
            if (!System.IO.File.Exists("log.xml"))
            {
                var document = new XDocument(
                    new XElement("logs"));

                document.Save("log.xml");
            }

            return XDocument.Load("log.xml")
                .Descendants("document")
                .Select(r => r.Attribute("id").Value);
        }

        private void AddToLog(IEnumerable<string> data)
        {
            var document = XDocument.Load("log.xml");
            document.Root.Add(
                new XElement("log",
                    new XAttribute("date", DateTime.Now.ToString()),
                    data.Select(r => new XElement("document", new XAttribute("id", r)))));

            document.Save("log.xml");
        }

        private void AddToLog(string id)
        {
            var document = XDocument.Load("log.xml");
            document.Root.Add(
                new XElement("log",
                    new XAttribute("date", DateTime.Now.ToString()),
                    new XElement("document", new XAttribute("id", id))));

            document.Save("log.xml");
        }


        private void fld1cUseJournal_CheckedChanged(object sender, EventArgs e)
        {
            this.SetJournalType();
        }

        private EDEX_1C2CommerceML.I1C Get1CContext()
        {
            EDEX_1C2CommerceML.I1C context;

            switch ((string)fld1cVersion.SelectedItem)
            {
                case "7.7":
                    context = new EDEX_1C2CommerceML._1Cv77(fld1cConnectionString.Text);
                    break;
                case "8.1":
                    context = new EDEX_1C2CommerceML._1Cv81(fld1cConnectionString.Text);
                    break;
                case "8.2":
                    context = new EDEX_1C2CommerceML._1Cv82(fld1cConnectionString.Text);
                    break;
                default:
                    context = null;
                    break;
            }
            return context;
        }

        private void label9_Click(object sender, EventArgs e)
        {

        }

        private void label5_Click(object sender, EventArgs e)
        {

        }

        private void lbl1cPath_Click(object sender, EventArgs e)
        {

        }

        private void Form1_Load(object sender, EventArgs e)
        {

        }

        private void btnCancel_Click(object sender, EventArgs e)
        {
            Close();
        }

        private void cmdSetSuppliers_Click(object sender, EventArgs e)
        {
            var form = new frmSuppliersFilter();
            form.Show(this);
        }

        private void fld1cRef_TextChanged(object sender, EventArgs e)
        {
            this.MakeConnectionString();
        }

    }
}
